﻿using System.Collections.Generic;
using System.Diagnostics;
using Flatland.GeneticProgramming.CoreTypes;
using Flatland.GeneticProgramming.SyntaxTree;

/**
* 
* Copyright (c) 2012 Anders Høst Kjærgaard | ahkj@itu.dk
* 
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, 
* including without limitation the rights to use, copy, modify, merge, publish, distribute, 
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Flatland.GeneticProgramming.Crossovers {

    /// <summary>
    /// CrossoverTechnique defines an ICrosser implementation. Any new implementation of an ICrosser should add a CrossoverTechnique also,
    /// this facilitates that new strategies will automatically be included in the test suite.
    /// </summary>
    public enum CrossoverTechnique {
        /// <summary>
        /// Select common crossover point, i.e. Function with similar arity or Terminal, with no respect to subTrees.
        /// </summary>
        [GPTechnique(typeof(OnePointCrossover))]
        ONE_POINT_CROSS_OVER

    };

    /// <summary>
    /// Crossover that facilitates as a proxy for any implemented ICrosser defined by a CrossoverTechnique.
    /// </summary>
    public class Crossover : ICrossOver {

        /// <summary>
        /// The ICrossOver that will handles the crossover.
        /// </summary>
        private readonly ICrossOver _crosser;
        
        /// <summary>
        /// Private constructor. Use parameterized constructor instead.
        /// </summary>
        private Crossover() { }

        /// <summary>
        /// Constructor. Aggregates an actual ICrosser implementation.
        /// </summary>
        /// <param name="crossoverTechnique"></param>
        public Crossover(CrossoverTechnique crossoverTechnique){
            _crosser = (ICrossOver) GPTechnique.GetImplementer(typeof (CrossoverTechnique), (int) crossoverTechnique);
        }

        /// <summary>
        /// Cross the Tree objects of a list of Report.
        /// </summary>
        /// <param name="reports"></param>
        /// <param name="crossOverRate"></param>
        /// <param name="maxTreeDepth"> </param>
        public void Cross(List<Report> reports, double crossOverRate, int maxTreeDepth) {
            Debug.Assert(reports != null, "Argument was null", "reports in Crossover was null");
            Debug.Assert(_crosser != null, "ICrosser in Crossover was null");
            Debug.Assert(1 < reports.Count, "Illegal reports for cross over", "At leat 2 reports are required to perform cross over");
            _crosser.Cross(reports, crossOverRate, maxTreeDepth);
        }

        /// <summary>
        /// True if a crossover of the root nodes won't cause bloat.
        /// </summary>
        /// <param name="t1"></param>
        /// <param name="t2"></param>
        /// <returns></returns>
        public static bool BloatControl(Tree t1, Tree t2, int maxdepth){
            return t1.Depth() + t2.MaxDetpth() - 1 <= maxdepth && t2.Depth() + t1.MaxDetpth() - 1 <= maxdepth;
        }
    }
}
